package com.alibaba.citrus.ots.price.ability.functions.entity.activity;

import com.alibaba.citrus.ots.common.annotation.FunctionInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.util.SpringContextUtil;
import com.alibaba.citrus.ots.price.ability.functions.factory.activity.process.ActivityProcess;
import com.alibaba.citrus.ots.price.ability.functions.factory.activity.process.ActivityProcessManager;
import com.alibaba.citrus.ots.price.repository.ActivityQueryRepository;
import com.alibaba.citrus.ots.price.repository.ActivityWriteRepository;
import com.alibaba.cz.base.tool.log.Log;
import com.alibaba.fastjson.JSON;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.otsforecastsales.domian.activityterm.model.ActivityTerm;
import com.epoch.app.otspricecenter.dto.request.*;
import com.epoch.app.otspricecenter.dto.response.ActivityTermViewResponse;
import com.epoch.app.otspricecenter.model.enums.ActivityTypeEnum;
import com.epoch.app.otspricecenter.sdo.ActivityTermSDO;
import com.epoch.app.otspricecenter.sdo.ActivityUseRecordRelationSDO;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: qiaojiange
 * @create: 2021/10/17
 * @Description 活动项目实体
 */
@Data
public class ActivityTermEntity {

    private static Log log = Log.getLogger(ActivityTermEntity.class);
    /**
     * 活动项目
     */
    private ActivityTermSDO sdo;
    /**
     * 赠品列表
     */
    private List<String> giftIdList;

    /**
     * 赠品活动类型
     */
    private String giftActivityType;

    /**
     * 原品列表
     */
    private List<String> itemList = new ArrayList<>();

    /**
     * 是否需要更新的标
     */
    private boolean needSaveFlag = false;

    /**
     * 活动占用费用
     */
    private Long activityOccupyFee;

//    /**
//     * 活动占用数量
//     */
//    private Integer activityOccupyQuantity;

    /**
     * 坎级活动组合列表
     */
    private List<SegmentedActivityCombinationEntity> combinationEntityList;

    /**
     * 写入资源库
     */
    private static ActivityWriteRepository writeRepository = SpringContextUtil.getBean(ActivityWriteRepository.class);

    /**
     * 活动查询资源库
     */
    private static ActivityQueryRepository queryRepository = SpringContextUtil.getBean(ActivityQueryRepository.class);

    private static ActivityProcessManager manager = SpringContextUtil.getBean(ActivityProcessManager.class);

    /**
     * 坎级活动实体
     */
    private List<SegmentedActivityTermEntity> segmentedActivityTermEntityList;

    /**
     * 同一个公用组中的所有的货品 id,特价的映射关系
     * @param 货品 ID，特价
     * @return
     */
    private Map<String,String> itemSpecialPriceMap;

    /**
     * 通用组标识
     */
    private String commonGroupFlag;
    /**
     * 存储term 中的原始数据的快照信息，方便活动占用排查问题使用
     */
    private String snapshot;

    public static ActivityTermEntity of(ActivityTermSDO sdo) {
        ActivityTermEntity termEntity = new ActivityTermEntity();
        termEntity.setSdo(sdo);
        termEntity.setSnapshot(JSON.toJSONString(sdo));
        return termEntity;
    }

    public String obtainActivityTermId() {
        return sdo.getActivityTermId();
    }

    public String obtainBusinessFormat() {
        return sdo.getBusinessFormat();
    }

    public String obtainBrand() {
        return sdo.getBrand();
    }

    public String obtainItemCategory() {
        return sdo.getItemCategory();
    }

    public String obtainItemSubject() {
        return sdo.getItemSubject();
    }

    public String obtainSpecialOfferPrice(String activityType, ActivityInfoRequest request) {
        return manager.getActivityProcess(activityType).processSpecialOfferPrice(this, request);
    }

    public String obtainSpecialOfferPrice() {
        return sdo.getSpecialOfferPrice();
    }

    public String obtainFacadeDescription() {
        return sdo.getFacadeDescription();
    }

    public Long obtainApplyFee() {
        return sdo.getApplyFee();
    }

    public Integer obtainApplyItemQuantity() {
        return sdo.getApplyItemQuantity();
    }

    public Integer obtainActivityOccupyQuantity() {
        return sdo.getActivityOccupyQuantity();
    }

    public Long obtainActivityOccupyFee() {
        return sdo.getActivityOccupyFee();
    }

    public Integer obtainActivityRemainingQuantity() {
        return sdo.getApplyItemQuantity() - sdo.getActivityOccupyQuantity();
    }

    public Long obtainActivityRemainingFee() {
        return sdo.getApplyFee() - sdo.getActivityOccupyFee();
    }

    public String obtainSalesUnit() {
        return sdo.getSalesUnit();
    }

    public Integer obtainVersion() {
        return sdo.getVersion();
    }

    /**
     * 获取赠品列表
     *
     * @return
     */
    public List<ActivityItemInfo> obtainGiftList(String activityType, ActivityInfoRequest request) {
        return manager.getActivityProcess(activityType).processGift(this, request);
    }

    public String obtainGiftType(){
        return this.giftActivityType == null ? null : this.giftActivityType;
    }

    /**
     * 更新活动数量和金额
     *
     * @param termRequest                 请求
     * @param activityType                活动类型
     * @param participateSuccessData
     * @return
     */
    public Boolean judgeOccupyQuantityAndFee(ParticipateActivityTermRequest termRequest, String activityType, Long[] participateSuccessData) {
//        更新占用活动数量
        Boolean occupyQuantityFlag = this.calculateOccupyQuantity(termRequest, activityType, participateSuccessData);
//        更新占用活动金额
        Boolean occupyFeeFlag = this.calculateOccupyFee(termRequest, activityType, participateSuccessData);
        return occupyQuantityFlag && occupyFeeFlag;
    }

    /**
     * 更新活动数量和金额_活动回补, 注意该方法只是内存修改，没有保存到数据库的逻辑
     *
     * @param termRequest 请求
     * @param activityEntity 请求
     * @return
     */
    public Boolean updateOccupyQuantityAndFeeForCover(CoverActivityTermRequest termRequest,ActivityEntity activityEntity) {
        /**
         * 更新占用活动数量
         */
        Boolean occupyQuantityFlag = this.updateOccupyQuantityForCover(termRequest,activityEntity);
        /**
         * 更新占用活动金额
         */
        Boolean occupyFeeFlag = this.updateOccupyFeeForCover(termRequest,activityEntity);

        return occupyQuantityFlag && occupyFeeFlag;

    }

    /**
     * 更新占用的金额
     *
     * @param termRequest 项目请求
     * @param participateSuccessDate
     * @return
     */
    @FunctionInvoker(printLog = true)
    private Boolean calculateOccupyFee(ParticipateActivityTermRequest termRequest, String activityType, Long[] participateSuccessDate) {
        ActivityProcess activityProcess = manager.getActivityProcess(activityType);
        //本次预占用费用
        long thisPreOccupyFee = activityProcess.calculatePreOccupyFee(this, termRequest);

        //校验延展金额
        Boolean checkPreOccupyFee = activityProcess.checkPreOccupyFee(this,thisPreOccupyFee);
        if (!checkPreOccupyFee) {
            return false;
        }

        participateSuccessDate[1] = thisPreOccupyFee;
        needSaveFlag = true;
        return true;
    }

    /**
     * 更新占用的金额_回补
     *
     * @param termRequest 项目请求
     * @return
     */
    @FunctionInvoker
    private Boolean updateOccupyFeeForCover(CoverActivityTermRequest termRequest,ActivityEntity activityEntity) {
        //ActivityItemInfo item = termRequest.getItem();
        ActivityUseRecordRelationSDO useSDO = activityEntity.getUseEntity().getActivityUseRecordRelationSDO();
        if(Objects.isNull(useSDO)){
            throw new FacadeException("OTS-08-002-01-16-007");
        }
        Long thisPreOccupyFee =useSDO.getActivityOccupyFee();
        //本次预占用费用
        //long thisPreOccupyFee = item.getItemPrice() * item.getItemQuantity();
        Long activityOccupyFee = this.obtainActivityOccupyFee() - useSDO.getActivityOccupyFee();
        if (activityOccupyFee < 0) {
            log.error("活动占用回补数量失败！活动申请费用:{},活动已占用费用:{},本次申请费用:{}",
                    this.obtainApplyFee(), this.obtainActivityOccupyFee(), thisPreOccupyFee);
            return false;
        }
        this.sdo.setActivityOccupyFee(activityOccupyFee);
        this.sdo.setVersion(termRequest.getVersion());
        needSaveFlag = true;
        return true;
    }

    public Result<List<ActivityTermViewResponse>> loadPromotionDetailPageList() {
        return queryRepository.queryPromotionDetailPageList(this.sdo);
    }


    /**
     * 更新占用的数量
     *
     * @param termRequest                 项目请求
     * @param participateSuccessItemCount
     * @return
     */
    private Boolean calculateOccupyQuantity(ParticipateActivityTermRequest termRequest, String activityType, Long[] participateSuccessItemCount) {
//        补货活动不占用活动数量
        if (ActivityTypeEnum.REPLENISHMENT.getValue().equals(activityType)) {
            participateSuccessItemCount[0] = 0L;
            return true;
        }

        ActivityProcess activityProcess = manager.getActivityProcess(activityType);
        Integer preOccupyQuantity = activityProcess.calculateOccupyQuantity(this, termRequest);

        Boolean checkQuantityFlag = activityProcess.checkPreOccupyQuantity(this, termRequest, preOccupyQuantity);
        if (!checkQuantityFlag) {
            return false;
        }

        //占用成功的数量
        participateSuccessItemCount[0] = preOccupyQuantity.longValue();
        needSaveFlag = true;
        return true;
    }


    /**
     * 更新占用的数量_活动占用量回补
     *
     * @param termRequest 项目请求
     * @return
     */
    @FunctionInvoker
    private Boolean updateOccupyQuantityForCover(CoverActivityTermRequest termRequest,ActivityEntity activityEntity) {
        //    这个地方要进行判断
        ActivityUseRecordRelationSDO useSDO = activityEntity.getUseEntity().getActivityUseRecordRelationSDO();
        if(Objects.isNull(useSDO)){
            log.error("活动回补失败,该订单没有活动使用记录");
            throw new FacadeException("OTS-08-002-01-16-007");
        }

        Integer itemQuantity = this.obtainActivityOccupyQuantity().intValue() - useSDO.getItemQuantity().intValue();
        //活动回补时，进行活动占补量的判断
        if (itemQuantity < 0) {
            log.error("活动占用量不够回补，该货品回补活动失败！活动回补活动量:{}, 已经占用的活动量:{},本次要占用的活动量:{}",
                    this.sdo.getApplyItemQuantity(), this.obtainActivityOccupyQuantity(), itemQuantity);
            return false;
        }

        this.sdo.setActivityOccupyQuantity(itemQuantity);
        this.sdo.setVersion(termRequest.getVersion());
        needSaveFlag = true;
        return true;
    }


    /**
     * 保存到数据库
     */
    public Boolean save() {
        if (!needSaveFlag) {
            return false;
        }
        return writeRepository.update(this.sdo);
    }

    /**
     * 获取原品 id
     *
     * @return
     */
    public String obtainItemId() {
        return sdo.getItemId();
    }

    /**
     * 获取赠品 id
     *
     * @return
     */
    public String obtainGiftId() {
        return sdo.getGiftId();
    }

    /**
     * 获取原品数量
     *
     * @return
     */
    public Integer obtainItemQuantity() {
        return sdo.getItemQuantity();
    }

    /**
     * 货品数量
     *
     * @param itemQuantity 货品数量
     */
    public void setActivityOccupyQuantity(Integer itemQuantity) {
        this.sdo.setActivityOccupyQuantity(itemQuantity);
    }

    /**
     * 设置版本
     *
     * @param version 版本号
     */
    public void setVersion(Integer version) {
        this.sdo.setVersion(version);
    }

    /**
     * 设置活动占用金额
     *
     * @param activityOccupyFee 活动占用金额
     */
    public void setActivityOccupyFee(long activityOccupyFee) {
        this.sdo.setActivityOccupyFee(activityOccupyFee);
    }

    /**
     * 获取赠品数量
     *
     * @return
     */
    public Integer obtainGiftQuantity() {
        return this.sdo.getGiftQuantity();
    }

    public Result<List<String>> queryItemCodes() {
        return queryRepository.queryItemCodesByActivityId(this.sdo);
    }

    public Result<List<String>> queryGiftCodes() {
        return queryRepository.queryGiftCodesByActivityId(this.sdo);
    }

    /**
     * 包含原品 ID
     *
     * @param itemId 原品 ID
     * @return true: 包含，false:不包含
     */
    public boolean containItemId(String itemId) {
        return StringUtils.isNotBlank(this.obtainItemId()) ? this.obtainItemId().equals(itemId) : this.getItemList().contains(itemId);
    }

    /**
     * 原品 ID 或者原品 ID 列表是不空的
     *
     * @return true: 不为空， false: 为空
     */
    public boolean itemIdOrItemIdListIsNotNull() {
        return StringUtils.isNotBlank(this.obtainItemId()) || CollectionUtils.isNotEmpty(this.getItemList());
    }

    /**
     * 当前的活动项目申请的总金额和总费用预占的校验
     * @return
     * @param quantitySum
     * @param feeSum
     */
    public Boolean isCanOccupyTerm(Integer quantitySum, Long feeSum) {
        //活动剩余量
        Integer remainingQuantity = this.obtainActivityRemainingQuantity();
        //活动剩余量不够
        if (remainingQuantity < quantitySum) {
            log.error("活动占用数量超出申请数量!" +
                    "活动申请量：" + this.obtainApplyItemQuantity() +
                    " 活动已占用量：" + this.obtainActivityOccupyQuantity() +
                    " 活动剩余量：" + remainingQuantity +
                    " 本次活动预占用量：" + quantitySum);
            return false;
        }

        //活动剩余费用
        Long remainingFee = this.obtainActivityRemainingFee();

        //活动剩余量不够
        if (remainingFee < feeSum) {
            log.error("活动占用费用超出申请数量!" +
                    "活动申请费用：" + this.obtainApplyFee() +
                    "活动已占用费用：" + this.obtainActivityOccupyFee() +
                    "活动剩余费用：" + remainingFee +
                    "活动占用费用：" + feeSum);
            return false;
        }
        return true;
    }

    public Map<String, List<String>> queryActivityAndItermMap(Map<String, String> activityMap) {
        List<ActivityTerm> activityTerms = queryRepository.queryActivityAndItermMap(activityMap);

        Map<String, List<ActivityTerm>> map = activityTerms.stream().
                collect(Collectors.groupingBy(activityTerm -> activityTerm.getActivityId()
                        + "_" + activityTerm.getActivityTermId()));
        if(MapUtils.isEmpty(map)){
            return new HashMap<>();
        }

        Map<String, List<String>> resultMap = map.entrySet().stream().collect(
                Collectors.toMap(e1 -> e1.getKey(), e2 -> e2.getValue().
                        stream().map(ActivityTerm::getItemId).
                        distinct().filter(StringUtils::isNotBlank).collect(Collectors.toList())));
        if(MapUtils.isEmpty(resultMap)){
            return new HashMap<>();
        }
        return resultMap;
    }

    public Map<String, List<String>> queryActivityAndGiftMap(Map<String, String> activityMap) {
        List<ActivityTerm> activityTerms = queryRepository.queryActivityAndGiftMap(activityMap);

        Map<String, List<ActivityTerm>> map = activityTerms.stream().
                collect(Collectors.groupingBy(activityTerm -> activityTerm.getActivityId()
                        + "_" + activityTerm.getActivityTermId()));
        if(MapUtils.isEmpty(map)){
            return new HashMap<>();
        }

        Map<String, List<String>> resultMap = map.entrySet().stream().collect(
                Collectors.toMap(e1 -> e1.getKey(), e2 -> e2.getValue().
                        stream().map(ActivityTerm::getGiftId).
                        distinct().filter(StringUtils::isNotBlank).collect(Collectors.toList())));
        if(MapUtils.isEmpty(resultMap)){
            return new HashMap<>();
        }
        return resultMap;
    }

    public String obtainIntensityOfActivityDesc() {
        return sdo.getIntensityOfActivityDesc();
    }

    /**
     * 保存到数据库,不判断版本锁
     * @return
     */
    @FunctionInvoker
    public Boolean saveNotForVersion() {
        if (!needSaveFlag) {
            return false;
        }
        return writeRepository.updateNotForVersion(this.sdo);
    }

    /**
     * 原品信息获取用于活动列表导出功能
     * @param activityMap
     * @return
     */
    public Map<String, List<String>> queryActivityAndItermMapExport(Map<String, String> activityMap) {
        List<ActivityTerm> activityTerms = queryRepository.queryActivityAndItermMapForExport(activityMap);

        Map<String, List<ActivityTerm>> map = activityTerms.stream().
                collect(Collectors.groupingBy(activityTerm -> activityTerm.getActivityId()
                        + "_" + activityTerm.getActivityTermId()));
        if(MapUtils.isEmpty(map)){
            return new HashMap<>();
        }

        Map<String, List<String>> resultMap = map.entrySet().stream().collect(
                Collectors.toMap(e1 -> e1.getKey(), e2 -> e2.getValue().
                        stream().map(ActivityTerm::getItemId).
                        distinct().filter(StringUtils::isNotBlank).collect(Collectors.toList())));
        if(MapUtils.isEmpty(resultMap)){
            return new HashMap<>();
        }
        return resultMap;
    }

    /**
     * 赠品列表获取用于活动列表导出功能
     * @param activityMap
     * @return
     */
    public Map<String, List<String>> queryActivityAndGiftMapExport(Map<String, String> activityMap) {
        List<ActivityTerm> activityTerms = queryRepository.queryActivityAndGiftMapForExport(activityMap);

        Map<String, List<ActivityTerm>> map = activityTerms.stream().
                collect(Collectors.groupingBy(activityTerm -> activityTerm.getActivityId()
                        + "_" + activityTerm.getActivityTermId()));
        if(MapUtils.isEmpty(map)){
            return new HashMap<>();
        }

        Map<String, List<String>> resultMap = map.entrySet().stream().collect(
                Collectors.toMap(e1 -> e1.getKey(), e2 -> e2.getValue().
                        stream().map(ActivityTerm::getGiftId).
                        distinct().filter(StringUtils::isNotBlank).collect(Collectors.toList())));
        if(MapUtils.isEmpty(resultMap)){
            return new HashMap<>();
        }
        return resultMap;
    }

    /**
     * 刷新占用数量和金额
     * @param quantitySum 数量和
     * @param feeSum 费用和
     * @param version 版本号
     */
    public void flushOccupyQuantityAndFee(Integer quantitySum, Long feeSum, Integer version) {
        Integer activityOccupyQuantity = this.obtainActivityOccupyQuantity();
        this.sdo.setActivityOccupyQuantity(activityOccupyQuantity + quantitySum);
        //乐观锁版本设置为请求体中的版本
        this.setVersion(version);

        //设置新的活动占用费用
        Long activityOccupyFee = this.obtainActivityOccupyFee();
        this.sdo.setActivityOccupyFee(activityOccupyFee + feeSum);
    }

    public String obtainActivityId() {
        return sdo.getActivityId();
    }
}
